#include <iostream>
#include <cmath>
using namespace std;

//==============================虚函数=================================================
// class Base{
// public:
//     virtual void func1(){
//         cout << "Base::func1" << endl;
//     }
//     void func2(){
//         cout << "Base::func2" << endl;
//     }
// };

// class A : public Base{
// public:
//     void func2(){//派生类中定义和基类中同名、形参列表一样的函数，而且基类中该函数没有virtual则是对基类中该函数的隐藏
//         cout << "A::func2" << endl;
//     }
//     void func1(){//对基类中虚函数的重写，override
//         cout << "A::func1" << endl;
//     }
// };

// int main(){
//     A a;
//     a.func1();
//     a.func2();

//     Base *p;
//     p = &a;
//     p->func2();//没有virtual所以调用的是基类中的func2
//     p->func1();//在基类中用virtual修饰了函数func1，在派生类中进行了重写，所以这里调用的是派生类中的函数

//     return 0;
// }


//======================================虚函数示例（Game）=====================================
// class Hero {
//     public:
//         void nothing (){
//             cout << "Hero do nothing" << endl;
//         }
//         virtual void huicheng (){
//             cout << "Hero normal huicheng" << endl;
//         }
// };

// class LiBai : public Hero{
//     public:
//         void huicheng(){
//             cout << "libai huicheng" << endl;
//         }

//         void nothing(){
//             cout << "libai do nothing" << endl;
//         }
// };

// class Caocao : public Hero{
//     public:
//         void huicheng(){
//             cout << "caocao huicheng" << endl;
//         }

//         void nothing(){
//             cout << "caocao do nothing" << endl;
//         }
// };

// class MiYue : public Hero{
//     public:
//         void nothing(){
//             cout << "miyue do nothing" << endl;
//         }
// };

// void go_back(Hero &h){
//     h.huicheng();
//     h.nothing();
// }

// int main(){
//     LiBai libai;
//     Caocao caocao;
//     MiYue miyue;

//     go_back(libai);
//     go_back(caocao);
//     go_back(miyue);
    

//     return 0;
// }

//===================================虚函数指针============================================
// class A
// {
//     public:
//         virtual void func1(){

//         }
//         virtual void func2(){

//         }
//         void func3(){

//         }
//         virtual void func4(){

//         }
// };

// class B : public A
// {
//     public:
//         virtual void func(){

//         }
//         virtual void func1(){//虚函数的重写

//         }
// };

// int main(){
//     A a;
//     cout << sizeof(a) << endl;
//     return 0;
// }

//===================================虚函数表和虚函数指针============================================
// class A
// {
//     public:
//         virtual void vfunc1();
//         virtual void vunc2();
//         void func1();
//         void func2();
//     private:
//         int data1,data2;
// };

// class B : public A{
//     public:
//         void vfunc1();
//         void func1();
//     private:
//         int data3;
// };

// class C : public B{
//     public:
//         void vfunc2();
//         void func2();
//     private:
//         int data1, data4;
// };

// int main(){
    

//     return 0;
// }

//============================================动态绑定=========================================
// class A
// {
//     public:
//         virtual void vfunc1(){
//             cout << "A::vfunc1" << endl;
//         }
//         virtual void vfunc2(){
//             cout << "A::vunc2" << endl;
//         }
//         void func1(){
//             cout << "A::func1" << endl;
//         }
//         void func2(){
//             cout << "A::func2" << endl;
//         }
// };

// class B : public A{
//     public:
//         void vfunc1(){
//             cout << "B::vfunc1" << endl;//重写虚函数也还是虚函数 所以写不写都可以
//         }
//         void func1(){//隐藏基类中的func1函数
//             cout << "B::func1" << endl;
//         }
//         void funcB(){
//             cout << "B::funcB" << endl;
//         }
// };

// int main(){
//     B b;
//     b.vfunc1(); // 调用 B::vfunc1
//     b.vfunc2();  // 调用 A::vunc2
//     b.func1();  // 调用 B::func1
//     b.func2();  // 调用 A::func2

//     A *p;
//     p = &b;
//     //在编译时不知道该函数调用的是哪个函数，只有在运行时指针变量指向了派生类对象，才知道调用的是哪个函数，叫动态联编
//     //而在运行时通过指针变量指向的对象的虚表指针，找到虚表，再通过虚表找到虚函数指针，最终调用对应的函数，这叫动态绑定
//     p->vfunc1(); // 调用 B::vfunc1 (动态联编)
//     p->vfunc2();  // 调用 A::vunc2 (动态联编)
//     p->func1();  // 调用 A::func1 (静态联编，即使 B::func1 隐藏了 A::func1 也是调用基类中的f)
//     p->func2();  // 调用 A::func2 (静态联编)

//     // p->funcB(); // 错误，A类没有funcB函数 基类指针指向派生类对象时是不能调用派生类中独有的成员函数的

//     return 0;
// }
// /*如果有基类指针指向派生类对象，并且通过基类指针调用某些函数时，编译器是如何处理的
//  *编译器会先检查被调用的函数是否为虚函数，如果f不是虚函数，采用静态编译，直接调用基类中的函数f，不论派生类是否隐藏了基类中的f函数
//  *如果函数f是虚函数，（编译时是不知道该函数的调用到底是哪个函数，在程序运行时指针变量指向了派生类，通过该指针能够找到对象的虚表指针以及虚表才会确认），会访问被指向（被引用）的派生类对象中的虚函数表找到调用该函数的虚函数指针
//  *如果派生类重写了基函数中的虚函数f，派生类的虚函数表中保存的是派生类中的f函数指针*/

//==================================================虚函数指针以及虚表===========================================
// typedef void (*FuncPtr)(); // 定义一个函数指针类型

// class Base {
//     public:
//         virtual void func1() { 
//             cout << "Base::func1" << endl; 
//         }
//         virtual void func2() {
//             cout << "Base::func2" << endl;
//         }
//         virtual void func3() {
//             cout << "Base::func3" << endl;
//         }
// };

// typedef long long u64_t;

// int main(){ 
//     Base b;
//     printf("%p\n", (u64_t *)(&b));//&b是对象b的地址，是Base*类型，强制转换为int*类型。 对象b的地址，也就是存放虚表指针的地址，转换为u64_t*类型输出即虚表指针

//     printf("%p\n", (u64_t *)(*(u64_t *)(&b)));//存放虚表指针的地址&_vfptr就是上述(int*)(&b), *(int*)(&b)就是*(&_vfptr),即_vfptr，也就是虚表指针的值，是一个地址，强制转换为u64_t*类型，以指针类型输出该地址的值即虚表指针

//     printf("%p\n", (u64_t *)(*(u64_t*)(&b)) + 0);//虚表指针的值加0，还是虚表指针的值
//     printf("%p\n", (u64_t *)(*(u64_t*)(&b)) + 1);//虚表指针的值加1，指向虚表中的第二个虚函数的地址
//     printf("%p\n", (u64_t *)(*(u64_t*)(&b)) + 2);//虚表指针的值加2，指向虚表中的第三个虚函数的地址

//     printf("%p\n", *((u64_t *)(*(u64_t*)(&b)) + 0));//输出虚表指针指向的值，也就是第一个虚函数的地址
//     printf("%p\n", *((u64_t *)(*(u64_t*)(&b)) + 1));//第二个虚函数的地址
//     printf("%p\n", *((u64_t *)(*(u64_t*)(&b)) + 2));//第三个虚函数的地址

//     //*((u64_t *)(*(u64_t*)(&b)) + 2)代表一个函数指针，指向上述虚函数
//     FuncPtr p;
//     p = (FuncPtr)(*((u64_t *)(*(u64_t*)(&b)) + 2));// 将第三个虚函数的地址赋值给函数指针p
//     p(); // 调用第三个虚函数，即Base::func3
//     return 0;
// }

//===================================纯虚函数和抽象基类======================================
// class Hero{
//     public:
//         virtual void huicheng() = 0; // 纯虚函数
//         virtual void nothing() = 0; // 纯虚函数
//         virtual ~Hero() {} // 虚析构函数，确保派生类对象正确析构
// };
// //和虚函数的区别是没有函数体，直接“=0” 虚函数表里面的值也是0，表示没有实现
// //一个类如果有纯虚函数那么就是抽象类，不能被实例化，只能被继承
// class Libai:public Hero{
//     public:
//         void huicheng();//对派生类中重写基类中的纯虚函数的声明
// };

// void Libai::huicheng(){ //派生类中实现纯虚函数
//     cout << "Libai huicheng" << endl;
// }

// //纯虚函数在派生类中要重新声明

//=================================================纯虚函数实例==============================================
// typedef unsigned int u32_t;

// class shape{
//     public:
//         virtual double getPermiter() = 0; // 纯虚函数
//         virtual double getArea() = 0; // 纯虚函数
//         virtual ~shape() {} // 虚析构函数
// };

// class Trangle : public shape{
//     public:
//         Trangle():_a(10), _b(10), _c(10) {} // 默认构造函数
//         Trangle(u32_t a, u32_t b, u32_t c):_a(a), _b(b), _c(c) {}

//         double getPermiter() override { // 重写纯虚函数
//             _permiter = _a + _b + _c;
//             return double(_permiter);
//         }

//         double getArea() override { // 重写纯虚函数
//             double s = double(_permiter) / 2.0; // 海伦公式
//             _area = sqrt(s * (s - _a) * (s - _b) * (s - _c));
//             return _area;
//         }

//     private:
//         u32_t _a, _b, _c; // 三角形的三条边
//         u32_t _permiter; // 三角形的周长
//         double _area; // 三角形的面积

// };

// class Circle : public shape{
//     public:
//         Circle():_r(10) {} // 默认构造函数
//         Circle(u32_t r):_r(r) {}

//         double getPermiter() override { // 重写纯虚函数
//             _permiter = 2 * Pi * _r; // 圆的周长公式
//             return _permiter;
//         }

//         double getArea() override { // 重写纯虚函数
//             _area = Pi * _r * _r; // 圆的面积公式
//             return _area;
//         }

//     private:
//         static double Pi;//声明一个静态成员变量
//         u32_t _r; // 圆的半径
//         double _permiter; // 圆的周长
//         double _area; // 圆的面积
// };

// double Circle::Pi = 3.14159265358979323846; // 定义静态成员变量

// int main(){
//     Trangle t;
//     cout << "三角形的周长: " << t.getPermiter() << endl;
//     Circle c;
//     cout << "圆的周长: " << c.getPermiter() << endl;
//     cout << "圆的面积: " << c.getArea() << endl;

//     //用一个数组来保存一个三角形和一个圆形 要用基类数组
//     shape *shapes[2];
//     shapes[0] = &t; // 将三角形对象的地址赋给基类指针
//     shapes[1] = &c; // 将圆形对象的地址赋给基类指针
//     for(int i = 0; i < 2; i++){
//         cout << "第" << i + 1 << "个图形的周长: " << shapes[i]->getPermiter() << endl;
//         cout << "第" << i + 1 << "个图形的面积: " << shapes[i]->getArea() << endl;
//     }

//     return 0;
// }

//===================================虚析构函数======================================
class A{
    public:
        A(){
            cout << "A::A()" << endl;
        }

        // virtual ~A(){ // 虚析构函数
        //     cout << "A::~A()" << endl;
        // }

        ~A(){ // 非虚析构函数
            cout << "A::~A()" << endl;
        }
};

class B : public A{
    public:
        B(){
            cout << "B::B()" << endl;
        }

        ~B(){ // 非虚析构函数
            cout << "B::~B()" << endl;
        }
};

int main(){
    //A a;
    //B b;//定义一个派生类对象时，先调用基类构造函数在调用派生类构造函数，析构函数相反
    
    A *p = new B(); // 基类指针指向派生类对象 构造一个派生类对象
    delete p; // 删除基类指针指向的派生类对象 通过基类指针释放一个派生类对象
    //如果基类的析构函数是虚函数，那么会先调用派生类的析构函数再调用基类的析构函数
    //如果基类的析构函数不是虚函数，那么只会调用基类的析构函数，不会调用派生类的析构函数，这会导致内存泄漏
    //所以在基类中定义虚析构函数是一个好习惯，确保派生类对象被正确析构
    return 0;
}